1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.math;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.math.DoubleUtils.IMPLICIT_BIT;
21 import static com.google.common.math.DoubleUtils.SIGNIFICAND_BITS;
22 import static com.google.common.math.DoubleUtils.getSignificand;
23 import static com.google.common.math.DoubleUtils.isFinite;
24 import static com.google.common.math.DoubleUtils.isNormal;
25 import static com.google.common.math.DoubleUtils.scaleNormalize;
26 import static com.google.common.math.MathPreconditions.checkInRange;
27 import static com.google.common.math.MathPreconditions.checkNonNegative;
28 import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
29 import static java.lang.Math.abs;
30 import static java.lang.Math.copySign;
31 import static java.lang.Math.getExponent;
32 import static java.lang.Math.log;
33 import static java.lang.Math.rint;
34
35 import com.google.common.annotations.GwtCompatible;
36 import com.google.common.annotations.GwtIncompatible;
37 import com.google.common.annotations.VisibleForTesting;
38 import com.google.common.primitives.Booleans;
39
40 import java.math.BigInteger;
41 import java.math.RoundingMode;
42 import java.util.Iterator;
43
44
45
46
47
48
49
50 @GwtCompatible(emulated = true)
51 public final class DoubleMath {
52
53
54
55
56 @GwtIncompatible("#isMathematicalInteger, com.google.common.math.DoubleUtils")
57 static double roundIntermediate(double x, RoundingMode mode) {
58 if (!isFinite(x)) {
59 throw new ArithmeticException("input is infinite or NaN");
60 }
61 switch (mode) {
62 case UNNECESSARY:
63 checkRoundingUnnecessary(isMathematicalInteger(x));
64 return x;
65
66 case FLOOR:
67 if (x >= 0.0 || isMathematicalInteger(x)) {
68 return x;
69 } else {
70 return x - 1.0;
71 }
72
73 case CEILING:
74 if (x <= 0.0 || isMathematicalInteger(x)) {
75 return x;
76 } else {
77 return x + 1.0;
78 }
79
80 case DOWN:
81 return x;
82
83 case UP:
84 if (isMathematicalInteger(x)) {
85 return x;
86 } else {
87 return x + Math.copySign(1.0, x);
88 }
89
90 case HALF_EVEN:
91 return rint(x);
92
93 case HALF_UP: {
94 double z = rint(x);
95 if (abs(x - z) == 0.5) {
96 return x + copySign(0.5, x);
97 } else {
98 return z;
99 }
100 }
101
102 case HALF_DOWN: {
103 double z = rint(x);
104 if (abs(x - z) == 0.5) {
105 return x;
106 } else {
107 return z;
108 }
109 }
110
111 default:
112 throw new AssertionError();
113 }
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 @GwtIncompatible("#roundIntermediate")
131 public static int roundToInt(double x, RoundingMode mode) {
132 double z = roundIntermediate(x, mode);
133 checkInRange(z > MIN_INT_AS_DOUBLE - 1.0 & z < MAX_INT_AS_DOUBLE + 1.0);
134 return (int) z;
135 }
136
137 private static final double MIN_INT_AS_DOUBLE = -0x1p31;
138 private static final double MAX_INT_AS_DOUBLE = 0x1p31 - 1.0;
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 @GwtIncompatible("#roundIntermediate")
155 public static long roundToLong(double x, RoundingMode mode) {
156 double z = roundIntermediate(x, mode);
157 checkInRange(MIN_LONG_AS_DOUBLE - z < 1.0 & z < MAX_LONG_AS_DOUBLE_PLUS_ONE);
158 return (long) z;
159 }
160
161 private static final double MIN_LONG_AS_DOUBLE = -0x1p63;
162
163
164
165
166 private static final double MAX_LONG_AS_DOUBLE_PLUS_ONE = 0x1p63;
167
168
169
170
171
172
173
174
175
176
177
178
179 @GwtIncompatible("#roundIntermediate, java.lang.Math.getExponent, "
180 + "com.google.common.math.DoubleUtils")
181 public static BigInteger roundToBigInteger(double x, RoundingMode mode) {
182 x = roundIntermediate(x, mode);
183 if (MIN_LONG_AS_DOUBLE - x < 1.0 & x < MAX_LONG_AS_DOUBLE_PLUS_ONE) {
184 return BigInteger.valueOf((long) x);
185 }
186 int exponent = getExponent(x);
187 long significand = getSignificand(x);
188 BigInteger result = BigInteger.valueOf(significand).shiftLeft(exponent - SIGNIFICAND_BITS);
189 return (x < 0) ? result.negate() : result;
190 }
191
192
193
194
195
196 @GwtIncompatible("com.google.common.math.DoubleUtils")
197 public static boolean isPowerOfTwo(double x) {
198 return x > 0.0 && isFinite(x) && LongMath.isPowerOfTwo(getSignificand(x));
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 public static double log2(double x) {
217 return log(x) / LN_2;
218 }
219
220 private static final double LN_2 = log(2);
221
222
223
224
225
226
227
228
229
230
231 @GwtIncompatible("java.lang.Math.getExponent, com.google.common.math.DoubleUtils")
232 @SuppressWarnings("fallthrough")
233 public static int log2(double x, RoundingMode mode) {
234 checkArgument(x > 0.0 && isFinite(x), "x must be positive and finite");
235 int exponent = getExponent(x);
236 if (!isNormal(x)) {
237 return log2(x * IMPLICIT_BIT, mode) - SIGNIFICAND_BITS;
238
239 }
240
241 boolean increment;
242 switch (mode) {
243 case UNNECESSARY:
244 checkRoundingUnnecessary(isPowerOfTwo(x));
245
246 case FLOOR:
247 increment = false;
248 break;
249 case CEILING:
250 increment = !isPowerOfTwo(x);
251 break;
252 case DOWN:
253 increment = exponent < 0 & !isPowerOfTwo(x);
254 break;
255 case UP:
256 increment = exponent >= 0 & !isPowerOfTwo(x);
257 break;
258 case HALF_DOWN:
259 case HALF_EVEN:
260 case HALF_UP:
261 double xScaled = scaleNormalize(x);
262
263
264 increment = (xScaled * xScaled) > 2.0;
265 break;
266 default:
267 throw new AssertionError();
268 }
269 return increment ? exponent + 1 : exponent;
270 }
271
272
273
274
275
276
277
278 @GwtIncompatible("java.lang.Math.getExponent, com.google.common.math.DoubleUtils")
279 public static boolean isMathematicalInteger(double x) {
280 return isFinite(x)
281 && (x == 0.0 ||
282 SIGNIFICAND_BITS - Long.numberOfTrailingZeros(getSignificand(x)) <= getExponent(x));
283 }
284
285
286
287
288
289
290
291
292
293
294 public static double factorial(int n) {
295 checkNonNegative("n", n);
296 if (n > MAX_FACTORIAL) {
297 return Double.POSITIVE_INFINITY;
298 } else {
299
300
301 double accum = 1.0;
302 for (int i = 1 + (n & ~0xf); i <= n; i++) {
303 accum *= i;
304 }
305 return accum * everySixteenthFactorial[n >> 4];
306 }
307 }
308
309 @VisibleForTesting
310 static final int MAX_FACTORIAL = 170;
311
312 @VisibleForTesting
313 static final double[] everySixteenthFactorial = {
314 0x1.0p0,
315 0x1.30777758p44,
316 0x1.956ad0aae33a4p117,
317 0x1.ee69a78d72cb6p202,
318 0x1.fe478ee34844ap295,
319 0x1.c619094edabffp394,
320 0x1.3638dd7bd6347p498,
321 0x1.7cac197cfe503p605,
322 0x1.1e5dfc140e1e5p716,
323 0x1.8ce85fadb707ep829,
324 0x1.95d5f3d928edep945};
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351 public static boolean fuzzyEquals(double a, double b, double tolerance) {
352 MathPreconditions.checkNonNegative("tolerance", tolerance);
353 return
354 Math.copySign(a - b, 1.0) <= tolerance
355
356 || (a == b)
357 || (Double.isNaN(a) && Double.isNaN(b));
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374 public static int fuzzyCompare(double a, double b, double tolerance) {
375 if (fuzzyEquals(a, b, tolerance)) {
376 return 0;
377 } else if (a < b) {
378 return -1;
379 } else if (a > b) {
380 return 1;
381 } else {
382 return Booleans.compare(Double.isNaN(a), Double.isNaN(b));
383 }
384 }
385
386 @GwtIncompatible("com.google.common.math.DoubleUtils")
387 private static final class MeanAccumulator {
388
389 private long count = 0;
390 private double mean = 0.0;
391
392 void add(double value) {
393 checkArgument(isFinite(value));
394 ++count;
395
396 mean += (value - mean) / count;
397 }
398
399 double mean() {
400 checkArgument(count > 0, "Cannot take mean of 0 values");
401 return mean;
402 }
403 }
404
405
406
407
408
409 @GwtIncompatible("MeanAccumulator")
410 public static double mean(double... values) {
411 MeanAccumulator accumulator = new MeanAccumulator();
412 for (double value : values) {
413 accumulator.add(value);
414 }
415 return accumulator.mean();
416 }
417
418
419
420
421
422 @GwtIncompatible("MeanAccumulator")
423 public static double mean(int... values) {
424 MeanAccumulator accumulator = new MeanAccumulator();
425 for (int value : values) {
426 accumulator.add(value);
427 }
428 return accumulator.mean();
429 }
430
431
432
433
434
435
436 @GwtIncompatible("MeanAccumulator")
437 public static double mean(long... values) {
438 MeanAccumulator accumulator = new MeanAccumulator();
439 for (long value : values) {
440 accumulator.add(value);
441 }
442 return accumulator.mean();
443 }
444
445
446
447
448
449
450 @GwtIncompatible("MeanAccumulator")
451 public static double mean(Iterable<? extends Number> values) {
452 MeanAccumulator accumulator = new MeanAccumulator();
453 for (Number value : values) {
454 accumulator.add(value.doubleValue());
455 }
456 return accumulator.mean();
457 }
458
459
460
461
462
463
464 @GwtIncompatible("MeanAccumulator")
465 public static double mean(Iterator<? extends Number> values) {
466 MeanAccumulator accumulator = new MeanAccumulator();
467 while (values.hasNext()) {
468 accumulator.add(values.next().doubleValue());
469 }
470 return accumulator.mean();
471 }
472
473 private DoubleMath() {}
474 }